#pragma once

#include "../comm/net.hpp"
#include "../comm/message.hpp"
#include <set>

namespace Server
{
    using namespace std;
    using namespace MuduoNet;
    using namespace Message;

    class ProviderManger
    {
    public:
        using ptr = shared_ptr<ProviderManger>;
        struct Provider
        {
            using ptr = shared_ptr<Provider>;
            BaseConnection::ptr conn;
            mutex _mutex;
            Address host;
            vector<string> methods;
            Provider(const BaseConnection::ptr &c, const Address &h) : conn(c), host(h)
            {
            }
            void AppendMethod(const string &method)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                methods.emplace_back(method);
            }
        };
        // 当一个服务提供者进行服务注册调用
        void AddProvider(const BaseConnection::ptr &c, const Address &h, const string &method)
        {
            Provider::ptr provider;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(c);
                if (it == _conns.end())
                {
                    // 没有
                    provider = make_shared<Provider>(c, h);
                    _conns.insert(make_pair(c, provider));
                }
                else
                {
                    provider = it->second;
                }
                // method方法的提供主机要多出一个，_providers新增数据
                auto &providers = _providers[method];
                providers.insert(provider);
            }
            // 向服务对象中新增一个所能提供的服务名称
            provider->AppendMethod(method);
        }
        // 当一个服务提供者断开的时候，获取他的信息---》用于下线通知
        Provider::ptr GetProvider(const BaseConnection::ptr &c)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(c);
            if (it == _conns.end())
            {
                return Provider::ptr();
            }
            return it->second;
        }
        // 当一个服务提供者断开的时候，删除他的关联信息
        void DelProvider(const BaseConnection::ptr &c)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(c);
            if (it == _conns.end())
            {
                return;
            }
            // 如果是提供者，看看提供了什么服务，从服务者提供信息中删除当前服务提供者
            for (auto &method : it->second->methods)
            {
                auto &providers = _providers[method];
                providers.erase(it->second);
            }
            _conns.erase(it);
        }
        vector<Address> MethodHost(const string &method)
        {
            unique_lock<mutex> lock(_mutex);
            auto it = _providers.find(method);
            if (it == nullptr)
            {
                return vector<Address>();
            }
            std::vector<Address> result;
            for (auto &provider : it->second)
            {
                result.push_back(provider->host);
            }
            return result;
        }

    private:
        mutex _mutex;
        unordered_map<string, set<Provider::ptr>> _providers;
        unordered_map<BaseConnection::ptr, Provider::ptr> _conns;
    };
    class DiscovererManger
    {
    public:
        using ptr = shared_ptr<DiscovererManger>;
        struct Discoverer
        {
            using ptr = shared_ptr<Discoverer>;
            mutex _mutex;
            BaseConnection::ptr conn; // 发现者的关联链接
            vector<string> methods;   // 发现过的服务名称
            Discoverer(const BaseConnection::ptr &c) : conn(c) {}
            void AppendMethod(const string &method)
            {
                unique_lock<mutex> lock(_mutex);
                methods.emplace_back(method);
            }
        };
        // 新增发现者，新增服务名称
        Discoverer::ptr AddDiscoverer(const BaseConnection::ptr &c, const string &method)
        {
            Discoverer::ptr discover;
            {
                unique_lock<mutex> lock(_mutex);
                auto it = _conns.find(c);
                if (it == _conns.end())
                {
                    discover = make_shared<Discoverer>(c);
                    _conns.insert(make_pair(c, discover));
                }
                else
                {
                    discover = it->second;
                }
                auto &discovers = _discoverers[method];
                discovers.insert(discover);
            }
            discover->AppendMethod(method);
            return discover;
        }
        // 找到关联者，删除发现者信息
        void DelDiscoverer(const BaseConnection::ptr &c)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(c);
            if (it == _conns.end())
            {
                // 没有找到连接对应的发现者信息，代表客户端不是一个服务发现者
                return;
            }
            for (auto &method : it->second->methods)
            {
                auto &discoverers = _discoverers[method];
                discoverers.erase(it->second);
            }
            _conns.erase(it);
        }
        // 当一个新的服务提供者上线，则进行上线通知
        void OnlineNotify(const string &method, const Address &host)
        {
            return Notify(method, host, ServiceOptype::SERVICE_ONLINE);
        }
        // 当一个服务提供者下线，则进行下线通知
        void OfflineNotify(const string &method, const Address &host)
        {
            return Notify(method, host, ServiceOptype::SERVICE_OFFLINE);
        }

    private:
        void Notify(const string &method, const Address &host, ServiceOptype op)
        {
            unique_lock<mutex> lock(_mutex);
            auto it = _discoverers.find(method);
            if (it == _discoverers.end())
            {
                return;
            }
            auto msg_req = MessageFactory::create<ServiceRequest>();
            msg_req->SetId(UUID::uuid());
            msg_req->SetHost(host);
            msg_req->SetMethod(method);
            msg_req->SetMtype(Mtype::REQ_SERVICE);
            msg_req->SetServiceOp(op);

            for (auto &discoverer : it->second)
            {
                discoverer->conn->Send(msg_req);
            }
        }

    private:
        mutex _mutex;
        unordered_map<string, set<Discoverer::ptr>> _discoverers;
        unordered_map<BaseConnection::ptr, Discoverer::ptr> _conns;
    };

    class PDManger
    {
    public:
        using ptr = shared_ptr<PDManger>;
        PDManger() : _providerers(make_shared<ProviderManger>()),
                     _disconverers(std::make_shared<DiscovererManger>()) {}
        void OnServiceRequest(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
        {
            // 服务操作请求：服务注册/服务发现/
            ServiceOptype optype = msg->GetServiceOp();
            // 服务注册：
            //   1. 新增服务提供者；  2. 进行服务上线的通知
            if (optype == ServiceOptype::SERVICE_REGISTRY)
            {
                 ILog("%s:%d 注册服务 %s", msg->Host().first.c_str(), msg->Host().second, msg->GetMethod().c_str());
                _providerers->AddProvider(conn, msg->Host(), msg->GetMethod());
                _disconverers->OnlineNotify(msg->GetMethod(), msg->Host());
                return RegistryResponce(conn,msg);
            }
            else if (optype == ServiceOptype::SERVICE_DISCOVERY)
            {
                // 服务发现：
                //   1. 新增服务发现者
                ILog("客户端要进行 %s 服务发现！", msg->GetMethod().c_str());
                _disconverers->AddDiscoverer(conn, msg->GetMethod());
                return DiscoverResponce(conn,msg); 
            }
            else
            {
                ELog("收到服务操作请求，但是操作类型错误！");
                return ErrResponse(conn,msg);
            }
        }
        void OnConnShutdown(const BaseConnection::ptr &conn)
        {
            auto provider = _providerers->GetProvider(conn);
            if (provider.get() != nullptr)
            {
                ILog("%s:%d 服务下线", provider->host.first.c_str(),provider->host.second);
                for (auto &method : provider->methods)
                {
                    _disconverers->OfflineNotify(method, provider->host);
                }
                _providerers->DelProvider(conn);
            }
            _disconverers->DelDiscoverer(conn);
        }

    private:
        void ErrResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
        {
            auto msg_rsp = MessageFactory::create<ServiceResponse>();
            msg_rsp->SetId(msg->GetRid());
            msg_rsp->SetMtype(Mtype::RSP_SERVICE);
            msg_rsp->SetOptype(ServiceOptype::SERVICE_UNKNOW);
            msg_rsp->SetRcode(RCode::RCODE_INVALID_OPTYPE);
            conn->Send(msg_rsp);
        }
        void RegistryResponce(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
        {
            auto msg_rsp = MessageFactory::create<ServiceResponse>();
            msg_rsp->SetId(msg->GetRid());
            msg_rsp->SetMtype(Mtype::RSP_SERVICE);
            msg_rsp->SetOptype(ServiceOptype::SERVICE_REGISTRY);
            msg_rsp->SetRcode(RCode::RCODE_OK);
            conn->Send(msg_rsp);
        }
        void DiscoverResponce(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg)
        {
            auto msg_rsp = MessageFactory::create<ServiceResponse>();
            msg_rsp->SetId(msg->GetRid());
            msg_rsp->SetMtype(Mtype::RSP_SERVICE);
            msg_rsp->SetOptype(ServiceOptype::SERVICE_DISCOVERY);

            vector<Address> hosts=_providerers->MethodHost(msg->GetMethod());
            if(hosts.empty())
            {
                msg_rsp->SetRcode(RCode::RCODE_NOT_FOUND_SERVICE);
                        return conn->Send(msg_rsp);
            }
            msg_rsp->SetRcode(RCode::RCODE_OK);
            msg_rsp->SetMethod(msg->GetMethod());
            msg_rsp->SetHost(hosts);
            return conn->Send(msg_rsp);
        }
    private:
        ProviderManger::ptr _providerers;
        DiscovererManger::ptr _disconverers;
    };
}